package cn.changeforyou.demo.netty.server;

import cn.changeforyou.demo.netty.common.Data;
import cn.changeforyou.demo.netty.common.YbkjTcpDataDecoder;
import cn.changeforyou.demo.netty.common.YbkjTcpDataEncoder;
import cn.changeforyou.demo.netty.common.YbkjWebsocketDataDecodeHandler;
import cn.changeforyou.demo.netty.common.YbkjWebsocketDataEncodeHandler;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPipeline;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.timeout.IdleStateHandler;
import io.netty.util.CharsetUtil;
import java.util.List;

/**
 * 协议选择器，动态支持多种协议 WEBSOCKET TCP私有协议 Author: wangwei
 * @author zhyu
 */
public class ProtocolSelectorHandler extends ByteToMessageDecoder {

    private ServerHandler serverHandler;
    private YbkjTcpDataDecoder ybkjTcpDataDecoder = new YbkjTcpDataDecoder();
    private YbkjTcpDataEncoder ybkjTcpDataEncoder = new YbkjTcpDataEncoder();
    private ExceptionHandler exceptionHandler = new ExceptionHandler();
    private HttpObjectAggregator httpObjectAggregator = new HttpObjectAggregator(8192);
    private WebSocketServerProtocolHandler webSocketServerProtocolHandler = new WebSocketServerProtocolHandler(WEBSOCKET_PREFIX);

    private HttpServerCodec httpServerCodec = new HttpServerCodec();

    public ProtocolSelectorHandler(ServerHandler serverHandler) {
        this.serverHandler = serverHandler;
    }

    /**
     * websocket定义请求行前缀
     */
    private static final String WEBSOCKET_LINE_PREFIX = "GET /ws";
    /**
     * websocket的uri
     */
    private static final String WEBSOCKET_PREFIX = "/ws";
    /**
     * 检查10个字节，没有空格就是自定义协议
     */
    private static final int SPACE_LENGTH = 10;

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        ChannelPipeline pipeline = ctx.pipeline();
        pipeline.addLast(new IdleStateHandler(60, 0, 0));


        if (isWebSocketUrl(in)) {
            pipeline.addLast(httpServerCodec);
            pipeline.addLast(httpObjectAggregator);
            pipeline.addLast(webSocketServerProtocolHandler);
            pipeline.addLast(new YbkjWebsocketDataDecodeHandler());
            pipeline.addLast(new YbkjWebsocketDataEncodeHandler());
        } else if (isYbkjTcpProcotol(in)) {
            pipeline.addLast(ybkjTcpDataDecoder);
            pipeline.addLast(ybkjTcpDataEncoder);
        }
        pipeline.addLast(serverHandler);
        pipeline.addLast(exceptionHandler);
        pipeline.remove(this);
    }

    /**
     * 是否有websocket请求行前缀
     *
     * @param byteBuf
     * @return
     */
    private boolean isWebSocketUrl(ByteBuf byteBuf) {
        if (byteBuf.readableBytes() < WEBSOCKET_LINE_PREFIX.length()) {
            return false;
        }
        byteBuf.markReaderIndex();
        byte[] content = new byte[WEBSOCKET_LINE_PREFIX.length()];
        byteBuf.readBytes(content);
        byteBuf.resetReaderIndex();
        String s = new String(content, CharsetUtil.UTF_8);
        return s.equals(WEBSOCKET_LINE_PREFIX);
    }

    /**
     * 是否是自定义是有协议
     *
     * @param byteBuf
     * @return
     */
    private boolean isYbkjTcpProcotol(ByteBuf byteBuf) {
        byteBuf.markReaderIndex();
        byte[] content = new byte[SPACE_LENGTH];
        byteBuf.readBytes(content);
        byteBuf.resetReaderIndex();
        String s = new String(content, CharsetUtil.UTF_8);
        return s.equals(Data.HEAD);
    }

}
